技巧14 管理容器内服务的启动

Docker官方文档中清楚地表达了Docker容器并不是虚拟机。Docker容器和虚拟机之间一个关键的区别就是,容器是被设计成运行单个进程的。当该进程结束时,容器便会退出。这就是它和一台Linux虚拟机(或任意一个Linux操作系统)的不同之处,它没有init进程。

init进程在Linux操作系统上是以进程ID为1并且父进程ID为0的形式运行的。这个init进程可能会被叫作“init”或“systemd”。无论它叫什么,它的职责都是承担运行在该操作系统上的所有其他进程的维护工作。

如果开始实验Docker,用户可能会发现自己仍然有启动多个进程的需求。例如,用户可能会想要运行一些cron作业来收拾本地应用的日志文件,又或者在容器里配置一个内部的memcached服务器。如果选择走这条路,那么可能最终需要编写一个shell脚本来管理这些子进程的启动。实际上,用户将会效仿init进程的做法。别这么干!进程管理中的许多问题之前都已经被其他人遇到过了,并且已经在预打包系统里解决了。

不管在容器中运行多个进程的原因是什么,重要的是要避免重复造轮子。

问题

想要在一个容器里管理多个进程。

解决方案

使用Supervisor来管理容器中的进程。

我们将展示如何置备一个同时运行Tomcat和Apache Web服务器的容器,并使用Supervisor应用来管理进程的启动,以托管的方式启动和运行它。

首先,如代码清单3-13所示,在一个新的空目录里创建Dockerfile。

代码清单3-13 Supervisor示例Dockerfile

 FROM ubuntu:14.04  ⇽--- 从ubuntu:14.04开始
 ENV DEBIAN_FRONTEND noninteractive  ⇽--- 设置一个环境变量,表明此会话是非交互式的
 RUN apt-get update && apt-get install -y python-pip apache2 tomcat7  ⇽--- 安装python- pip(用来安装Supervisor)、apache2和tomcat7
 RUN pip install supervisor  ⇽--- 通过pip安装Supervisor
 RUN mkdir -p /var/lock/apache2  ⇽--- 
 RUN mkdir -p /var/run/apache2
 RUN mkdir -p /var/log/tomcat  ⇽--- 创建一些运行应用所需的维护目录
 RUN echo_supervisord_conf > /etc/supervisord.conf  ⇽--- 利用echo_supervisord_conf工具创建一个默认的supervisord配置文件
 ADD ./supervisord_add.conf /tmp/supervisord_add.conf  ⇽--- 将Apache和Tomcat的supervisord配置设定复制到镜像里,做好加到默认配置的准备
 RUN cat /tmp/supervisord_add.conf >> /etc/supervisord.conf  ⇽--- 将Apache和Tomcat的supervisord配置设定追加到supervisord的配置文件里
 RUN rm /tmp/supervisord_add.conf  ⇽--- 由于不再有用处了,删除之前上传的文件
 CMD ["supervisord","-c","/etc/supervisord.conf"]  ⇽--- 现在,只需要在容器启动时运行Supervisor即可

还需要配置Supervisor,指示它需要启动哪些应用,如代码清单3-14所示。

代码清单3-14 supervisord_add.conf

[supervisord]   ⇽--- 为supervisord声明全局配置块
 nodaemon=true  ⇽--- 设置成不要后台运行Supervisor进程,因为对容器来说它是一个前台进程
# apache
[program:apache2]   ⇽--- 声明新程序的代码块
 command=/bin/bash -c "source /etc/apache2/envvars && exec /usr/sbin/apache2
➥ -DFOREGROUND"  ⇽--- 用于启动在该代码块中声明的程序的命令
# tomcat
[program:tomcat]   ⇽--- 声明新程序的代码块
 command=service start tomcat  ⇽--- 用于启动在该代码块中声明的程序的命令
 redirect_stderr=true
 stdout_logfile=/var/log/tomcat/supervisor.log  ⇽--- 
 stderr_logfile=/var/log/tomcat/supervisor.error_log  ⇽--- 配置相关日志

由于用的是Dockerfile,因此可以借助标准的单个Docker命令来构建镜像。执行这条命令来完成这一构建过程:

docker build -t supervised .

现在可以运行构建好的镜像了,如代码清单3-15所示。

代码清单3-15 运行supervisord容器

$ docker run -p 9000:80 --name supervised supervised  ⇽--- 将容器的80端口映射到宿主机上的9000端口,给容器分配一个名字,然后指定要运行的镜像名称,即之前构建命令标记的那个
 2015-02-06 10:42:20,336 CRIT Supervisor running as root (no user in config
➥ file)   ⇽--- 启动Supervisor进程
 2015-02-06 10:42:20,344 INFO RPC interface 'supervisor' initialized
 2015-02-06 10:42:20,344 CRIT Server 'unix_http_server' running without any
➥ HTTP authentication checking
 2015-02-06 10:42:20,344 INFO supervisord started with pid 1  ⇽--- 启动Supervisor进程
 2015-02-06 10:42:21,346 INFO spawned: 'tomcat' with pid 12  ⇽--- 
 2015-02-06 10:42:21,348 INFO spawned: 'apache2' with pid 13  ⇽--- 启动被托管的进程
 2015-02-06 10:42:21,368 INFO reaped unknown pid 29
 2015-02-06 10:42:21,403 INFO reaped unknown pid 30
 2015-02-06 10:42:22,404 INFO success: tomcat entered RUNNING state, process  ⇽--- 
➥ has stayed up for > than 1 seconds (startsecs)
 2015-02-06 10:42:22,404 INFO success: apache2 entered RUNNING state, process
➥ has stayed up for > than 1 seconds (startsecs)  ⇽--- 被托管的进程被Supervisor识别为已经成功启动

如果访问http://localhost:9000,应该就能看到启动的Apache服务器的默认页面。

要清理容器,可以执行如下命令:

docker rm -f supervised

讨论

本技巧用Supervisor在Docker容器里管理多个进程。

如果读者对Supervisor的其他替代品有兴趣,还有一个runit,技巧12里介绍过的phusion基础镜像用到过它。

results matching ""

    No results matching ""